﻿using System;
using JTLeigh.Commerce.Spencer.Core.Common.Services;
using JTLeigh.Commerce.Spencer.Features.ProductImages.Business.Caches;
using JTLeigh.Commerce.Spencer.Features.ProductImages.Common;
using JTLeigh.Commerce.Spencer.Features.ProductImages.Common.Entities;
using JTLeigh.Commerce.Spencer.Features.ProductImages.Data.Providers;
using Microsoft.Practices.Unity;

namespace JTLeigh.Commerce.Spencer.Features.ProductImages.Business.Services
{

	/// <summary>
	/// An <see cref="IProductImageMetadataService"/> implementation that gets product image 
	/// metadata from the database with caching.
	/// </summary>
	public class ProductImageMetadataService : IProductImageMetadataService
	{

		#region Properties

		/// <summary>
		/// Gets or sets the product image metadata provider to use to get product image metadata 
		/// from the database.
		/// </summary>
		/// <value>An <see cref="IProductImageMetadataProvider"/> implementation.</value>
		[Dependency]
		public IProductImageMetadataProvider ProductImageMetadataProvider { get; set; }

		/// <summary>
		/// Gets or sets the product image metadata cache to use to cache product image metadata.
		/// </summary>
		[Dependency]
		public IProductImageMetadataCache ProductImageMetadataCache { get; set; }

		/// <summary>
		/// Gets or sets the exception handling service to use to handle exceptions.
		/// </summary>
		/// <value>An <see cref="IExceptionHandlingService"/> implementation.</value>
		[Dependency]
		public IExceptionHandlingService ExceptionHandlingService { get; set; }

		#endregion // Properties

		#region IProductImageMetadataService Members

		/// <summary>
		/// Gets a localized product image size by size identifier and culture identifier.
		/// </summary>
		/// <param name="tenantId">The tenant identifier <see cref="Guid"/> of the tenant whose
		/// product image size is to be retrieved.</param>
		/// <param name="sizeId">The size identifier <see cref="Guid"/> of the size to retrieve.</param>
		/// <param name="cultureId">The <see cref="Int32"/> LCID of the culture to use to retrieve
		/// culture-specific resources.</param>
		/// <returns>A <see cref="LocalizedProductImageSize"/>.</returns>
		public LocalizedProductImageSize GetProductImageSizeBySizeId(Guid tenantId, Guid sizeId, int cultureId)
		{
			ProductImageMetadata metadata;
			ProductImageSize size;
			ProductImageSizeLocalization localization;

			try
			{
				metadata = GetProductImageMetadataWithCaching(tenantId);
				if (!metadata.SizesBySizeId.TryGetValue(sizeId, out size))
				{
					return null;
				}
				size.Localizations.TryGetValue(cultureId, out localization);
				return new LocalizedProductImageSize(size, localization);
			}
			catch (Exception e)
			{
				ExceptionHandlingService.HandleException(tenantId, e, ProductImagesExceptionPolicy.Business);
				throw;
			}
		}

		/// <summary>
		/// Gets a localized product image size by well-known size code and culture identifier.
		/// </summary>
		/// <param name="tenantId">The tenant identifier <see cref="Guid"/> of the tenant whose
		/// product image size is to be retrieved.</param>
		/// <param name="wellKnownSizeCode">The well-known size code <see cref="Byte"/> of the size 
		/// to retrieve.</param>
		/// <param name="cultureId">The <see cref="Int32"/> LCID of the culture to use to retrieve
		/// culture-specific resources.</param>
		/// <returns>A <see cref="LocalizedProductImageSize"/>.</returns>
		public LocalizedProductImageSize GetProductImageSizeByWellKnownSizeCode(Guid tenantId, byte wellKnownSizeCode, int cultureId)
		{
			ProductImageMetadata metadata;
			ProductImageSize size;
			ProductImageSizeLocalization localization;

			try
			{
				metadata = GetProductImageMetadataWithCaching(tenantId);
				if (!metadata.SizesByWellKnowSizeCode.TryGetValue(wellKnownSizeCode, out size))
				{
					return null;
				}
				size.Localizations.TryGetValue(cultureId, out localization);
				return new LocalizedProductImageSize(size, localization);
			}
			catch (Exception e)
			{
				ExceptionHandlingService.HandleException(tenantId, e, ProductImagesExceptionPolicy.Business);
				throw;
			}
		}

		/// <summary>
		/// Gets a localized product image view by view identifier and culture identifier.
		/// </summary>
		/// <param name="tenantId">The tenant identifier <see cref="Guid"/> of the tenant whose
		/// product image view is to be retrieved.</param>
		/// <param name="viewId">The view identifier <see cref="Guid"/> of the view to retrieve.</param>
		/// <param name="cultureId">The <see cref="Int32"/> LCID of the culture to use to retrieve
		/// culture-specific resources.</param>
		/// <returns>A <see cref="LocalizedProductImageView"/>.</returns>
		public LocalizedProductImageView GetProductImageViewByViewId(Guid tenantId, Guid viewId, int cultureId)
		{
			ProductImageMetadata metadata;
			ProductImageView view;
			ProductImageViewLocalization localization;

			try
			{
				metadata = GetProductImageMetadataWithCaching(tenantId);
				if (!metadata.ViewsByViewId.TryGetValue(viewId, out view))
				{
					return null;
				}
				view.Localizations.TryGetValue(cultureId, out localization);
				return new LocalizedProductImageView(view, localization);
			}
			catch (Exception e)
			{
				ExceptionHandlingService.HandleException(tenantId, e, ProductImagesExceptionPolicy.Business);
				throw;
			}
		}

		/// <summary>
		/// Gets a localized product image view by well-known view code and culture identifier.
		/// </summary>
		/// <param name="tenantId">The tenant identifier <see cref="Guid"/> of the tenant whose
		/// product image view is to be retrieved.</param>
		/// <param name="wellKnownViewCode">The well-known view code <see cref="Byte"/> of the view 
		/// to retrieve.</param>
		/// <param name="cultureId">The <see cref="Int32"/> LCID of the culture to use to retrieve
		/// culture-specific resources.</param>
		/// <returns>A <see cref="LocalizedProductImageView"/>.</returns>
		public LocalizedProductImageView GetProductImageViewByWellKnownViewCode(Guid tenantId, byte wellKnownViewCode, int cultureId)
		{
			ProductImageMetadata metadata;
			ProductImageView view;
			ProductImageViewLocalization localization;

			try
			{
				metadata = GetProductImageMetadataWithCaching(tenantId);
				if (!metadata.ViewsByWellKnowViewCode.TryGetValue(wellKnownViewCode, out view))
				{
					return null;
				}
				view.Localizations.TryGetValue(cultureId, out localization);
				return new LocalizedProductImageView(view, localization);
			}
			catch (Exception e)
			{
				ExceptionHandlingService.HandleException(tenantId, e, ProductImagesExceptionPolicy.Business);
				throw;
			}
		}

		#endregion // IProductImageMetadataService Members

		#region Implementation

		private ProductImageMetadata GetProductImageMetadataWithCaching(Guid tenantId)
		{
			ProductImageMetadata metadata;

			metadata = ProductImageMetadataCache.GetProductImageMetadata(tenantId);
			if (metadata == null)
			{
				metadata = ProductImageMetadataProvider.GetProductImageMetadata(tenantId);
				ProductImageMetadataCache.SetProductImageMetadata(tenantId, metadata);
			}
			return metadata;
		}

		#endregion // Implementation

	}

}
